package cn.iocoder.yudao.framework.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.text.csv.CsvUtil;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.UtilityClass;

import java.util.ArrayList;
import java.util.List;

/**
 * <pre>
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 *  这里是文件说明
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * </pre>
 *
 * @author 山野羡民（1032694760@qq.com）
 * @since 2025/05/17
 */
@SuppressWarnings("unused")
@UtilityClass
public class BankUtils {
    private static final String BANK_BIN_CSV = "bank_bin.csv";
    private static final String BANK_CODE_CSV = "bank_code.csv";
    private static final List<BankBin> BANK_BINS = new ArrayList<>();
    private static final List<BankCode> BANK_CODES_DEFAULT = new ArrayList<>();
    private static final List<BankCode> BANK_CODES_MALLBOOK = new ArrayList<>();

    /**
     * 通过银行卡号获取所属银行识别码信息
     *
     * @param cardNo 银行卡号
     * @return 银行识别码信息
     */
    @Nullable
    public static BankBin getBankBinByCardNo(String cardNo) {
        if (cardNo == null) {
            return null;
        }
        cardNo = cardNo.replaceAll("\\s", "");
        if (cardNo.length() < 6) {
            return null;
        }
        String finalCardNo = cardNo;
        return getBins().stream()
                .filter(bankBin -> finalCardNo.startsWith(bankBin.getBin()))
                .findFirst()
                .orElse(null);
    }

    /**
     * 数据来源于 <a href="https://my.oschina.net/superbigfu/blog/175476">根据银行卡获取银行卡开户银行和类型</a>
     * <pre>
     * {@code
     *     public static void main(String[] args) {
     *         StringBuilder sb = new StringBuilder();
     *         sb.append("BIN,银行名称,卡种\n");
     *         for (int i = 0; i < bankBins.length; i++) {
     *             String[] parts = bankNames[i].split("\\.");
     *             String bank = parts[0];
     *             String cardType = parts.length > 1 ? parts[1] : "";
     *             sb.append(bankBin[i]).append(",");
     *             sb.append(bank).append(",");
     *             sb.append(cardType).append("\n");
     *         }
     *         System.out.println(sb);
     *     }
     * }
     * </pre>
     */
    @SuppressWarnings("SameReturnValue")
    @Nonnull
    public static List<BankBin> getBins() {
        if (CollUtil.isNotEmpty(BANK_BINS)) {
            // 只从 csv 加载一次
            return BANK_BINS;
        }
        // 从 csv 中加载数据
        List<CsvRow> rows = CsvUtil.getReader().read(ResourceUtil.getUtf8Reader(BANK_BIN_CSV)).getRows();
        // BIN,银行名称,卡种
        rows.remove(0); // 删除 header
        for (CsvRow row : rows) {
            BANK_BINS.add(new BankBin(row.get(0), row.get(1), row.get(2)));
        }
        return BANK_BINS;
    }

    /**
     * 数据来源于 <a href="https://blog.csdn.net/qq_38288606/article/details/116125450">通过银行卡号获取所属银行「支付宝」</a>
     */
    @SuppressWarnings("SameReturnValue")
    @Nonnull
    public static List<BankCode> getCodesByDefault() {
        if (CollUtil.isNotEmpty(BANK_CODES_DEFAULT)) {
            // 只从 csv 加载一次
            return BANK_CODES_DEFAULT;
        }
        // 从 csv 中加载数据
        List<CsvRow> rows = CsvUtil.getReader().read(ResourceUtil.getUtf8Reader(BANK_CODE_CSV)).getRows();
        // code,name
        rows.remove(0); // 删除 header
        for (CsvRow row : rows) {
            BANK_CODES_DEFAULT.add(new BankCode(row.get(0), row.get(1)));
        }
        return BANK_CODES_DEFAULT;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class BankBin {
        @JsonProperty("bin")
        private String bin;
        @JsonProperty("name")
        private String name;
        @JsonProperty("type")
        private String type;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class BankCode {
        @JsonProperty("code")
        private String code;
        @JsonProperty("name")
        private String name;
    }

    public static void main(String[] args) {
        System.out.println(getBankBinByCardNo("6222 8071 0267 1159 575"));
    }

}
